Web Component Interface
The ChartIQ sample templates, located in chartiq/examples/templates
, utilize W3C-standard web components. These components allow you to create custom tags with built-in programming logic, enabling you to personalize your interfaces.
By leveraging the Web Components specification, you can develop custom tags tailored to your needs. The library file componentUI.js
enhances functionality by offering basic data-binding capabilities and a streamlined infrastructure for constructing interfaces with web components.
See the complete list of ChartIQ web components.
Newly Rearchitected ChartIQ Web Components
ChartIQ Version 9.1.0 introduced a significant architectural update to our web components, which now support the use of dynamic and reactive attributes. This enhancement allows developers to easily customize and manipulate these web components, eliminating the need for invoking API methods that were previously required.
- Our web components can now emit events when their attributes change.
- For example, developers can easily listen to and handle these events using custom React hooks, which provide a flexible and efficient way to respond to attribute changes.
- Conversely, you can now send an event or change in state to a component by changing an attribute, allowing the component to react to this change. Previously, achieving this effect would require calling a function, which was more difficult and prone to error.
- A component can listen for these events even when it is not active or visible, making it particularly useful when changing themes.
- Similar to the way React manages state, events can be saved in local storage and then picked up by an attribute change when a particular component loads again.
These changes update our web component architecture to align with the latest patterns in framework development, providing developers, especially those working in frameworks like React, with a more modern and customizable library.
In addition to the dynamic and reactive attribute tags, the web component architecture offers several other benefits. These benefits include modularity, which makes the components flexible, reusable, and decoupled. It also enhances testing and debugging capabilities, and improves readability for developers, particularly those working with frameworks like React.
The updated web components also represent a notable achievement for ChartIQ as we significantly enhanced accessibility for visually impaired users. By ensuring comprehensive screen reader accessibility for menu options, drawing tools, pop-ups, and dialogues, we have made significant progress toward inclusivity and usability.
Note: Those using older versions of the library or legacy web components will not have the same features.
Legacy web components and documentation
All tutorials and API documentation from before the rearchitecting of our web components are available on the ChartIQ Legacy Documentation site, which is up-to-date with Version 8.9.0.
The latest versions of the library still include legacy web components and are found in chartiq/js/components-legacy.js
. However, if you plan to use them with Version 9.1.0 or later, there are important limitations to consider:
- You cannot mix and match old and new components. It's all or nothing.
- You cannot use legacy components with current html templates (i.e. templates from 9.1.0 and newer versions), and vice-versa. You must use your own custom or legacy template with the legacy components.
See the backwards compatibility instructions.
Web components 101
1: Web components are custom tags
Web components, such as ChartIQ tags, are self-contained and start as "custom tags" that can be named however you like, but they must include a hyphen. ChartIQ tags, for example, begin with "cq-".
Example ChartIQ web component:
Note: ChartIQ sample templates contain multiple cq-dialog
components. To allow for specific component selection in the following examples, we have added an ID. Additionally, ChartIQ components must be within the cq-context
tags in order for the web components to have control of the chart.
<cq-context>
<cq-dialog id="myDialog"><cq-dialog>
</cq-context>
Web components, like other tags, can be referenced using DOM methods such as querySelector()
and getElementById()
, and styled using CSS.
Starting with Version 9.1.2, each ChartIQ web component with custom styling has its own dedicated SASS file in the css/webcomponents/
folder. For instructions on custom styling, see the CSS Overview tutorial.
Note: One difference is that, unlike a div
, custom tags default to display: inline
rather than display: block
.
Example: Manipulating web components:
<style>
cq-dialog#myDialog {
background-color: black;
}
</style>
<script>
const dialogBox = document.getElementById("myDialog");
dialogBox.setAttribute('cq-title','Lorem ipsum');
dialogBox.open();
</script>
2: Web components are JavaScript objects
Web components must implement the HTMLElement interface, so they are typically created using "inheritance". Since web components are JavaScript objects, it is easy to make them do things. Inside a component, this
refers to the component itself. Thus, with a web component, you can combine HTML operations and business logic (such as calculating a study or saving an instance of the crosshairs to local storage) in one place.
Example: A component comes alive:
dialogBox.updateDialogTitle = function() {
this.setAttribute("cq-title","Hello world!");
};
dialogBox.updateDialogTitle();
One of the tough problems for most frameworks is making components work together. Usually this results in tight coupling, which makes most single page applications (SPA) increasingly difficult to manage as they grow in scale. Web components live in the DOM, which means that they are automatically organized and that selectors can be used to link them.
3: Web components observe life-cycle events
With the release of v9.1.0, our web components have been rearchitected to support a more modern approach by handling key lifecycle events. These events include connectedCallback()
, disconnectedCallback()
, adoptedCallback()
, and attributeChangedCallback()
. These lifecycle callbacks have been implemented to better align our web components with industry standards, making development and customization easier for developers.
Legacy web components from versions of the library older than 9.1.0 govern their life-cycles using callbacks that each legacy component automatically provides. Please consult the legacy documentation for more on how these work.
4: Web components can use templates
The template tag provides a clean, easy way to build dynamic content. Content inside a template tag is ignored by the browser, but is still visible when you inspect the HTML.
Example: Let's create a list:
<style>
cq-dialog#myDialog {
top: 30%;
left: 30%;
transform: translate(-50%, -50%)
}
</style>
<cq-dialog id="myDialog">
<template item>
<li></li>
</template>
<ul></ul>
</cq-dialog>
<script>
const dialogArray = [
"Dialog Item 1",
"Dialog Item 2",
"Dialog Item 3",
"Dialog Item 4",
"Dialog Item 5",
];
const dialogBox = document.getElementById("myDialog");
dialogBox.createListItem = function (str) {
const ul = this.node.find("ul");
const template = this.node.find("template[item]");
let newItem = CIQ.UI.makeFromTemplate(template)[0];
newItem.innerText = str;
// newItem.setAttribute('stxtap', 'handleClick()') <-- This will be used in a later example
ul.append(newItem);
};
dialogArray.forEach((item) => {
dialogBox.createListItem(item);
});
setTimeout(() => dialogBox.open());
</script>
In the example above we use a couple of patterns.
- First we create a template tag and fill it with the raw html that we want to use to build list items. We've given it an attribute name to make it easy to find with a selector.
Note: if you only have a single template in your web component you don't need an attribute to reference. - Inside of our component logic, once we've found our template within the DOM, we use the convenience method makeFromTemplate to convert the template into live HTML.
- Finally, we add the new HTML into the DOM where we want it.
This is an "imperative" approach to dynamic content, which is simple to follow. However, the component infrastructure does not support a "declarative" (data binding) approach. For data binding, you can explore other templating libraries available.
5: Web components are composable
You can compose web components together with other web components. This can be done at two levels. You can do this within a single HTML page.
Example: Compose one component with another:
<cq-dialog>
<cq-close></cq-close>
</cq-dialog>
In this example, developers can easily customize the web component by modifying the HTML. It is important to write the component "defensively" (without making too many assumptions about its content). This approach allows for the creation of ready-made components that can still be customized.
Additionally, web components can be designed to be "opaque," meaning that their contents are visible but not easily changed. This is done by placing the components in a separate file and importing them when needed.
Working With The ChartIQ Web Component Framework
Getting Started
Loading the Framework
To use the ChartIQ Web Component Framework you may include the following third party libraries:
perfect-scrollbar.esm.js
(used to style scrolling components such as menus).
Then include componentUI.js, which is part of the ChartIQ library. sample-template-advanced.html
and sample-template-basic.html
contain example code.
HTML tags that begin with "cq-" are web components that become enabled when you include componentUI.js.
Setting Up the Framework
You must set up the cq-context
element before you can use any of the library's web components.
The cq-context
element is a special element used by the chart library web components. It wraps all library web components and holds a reference to a specified ChartEngine
instance. This enables the web components to have direct control over the chart.
The cq-context
can be defined in one of two ways: a custom attribute or a custom element.
Custom Attribute:
Use this method when placing the chart in an existing html layout.
<div cq-context>
<!-- Chart & Chart UI Goes Here -->
</div>
Custom Element:
Use this method to define the container element more explicitly.
<cq-context>
<!-- Chart & Chart UI Goes Here -->
</cq-context>
To host multiple charts on a screen you should set up a cq-context
element for each ChartEngine
instance.
Modifying the default configurations
The ChartIQ library includes a default configuration object that establishes a basic chart configuration.
When creating your chart and making modifications to suit your needs, it is recommended to make changes to the configuration object directly in your template before calling config.createChart()
, rather than modifying the default configuration object. Modifying defaultConfiguration.js
may result in issues when upgrading to newer versions.
Examples:
The below code pasted into one of our sample templates will change the weekly periodicity to '2-day' periodicity. See the CIQ.UI.Layout#setPeriodicity API docs for more information.
const newPeriodicityObj = { type: "item", label: "2 D", tap: "Layout.setPeriodicity", value: [2, 1, "day"] };
config.menus.period.content[1] = newPeriodicityObj;
Changes the initial symbol of the chart.
config.initialSymbol.symbol = "XYZ";
See the Chart Configuration Tutorial to learn more about the default configuration object.
Creating Web Components: BaseComponent and ContextTag
In order to interact with the UI framework, components should be derived from the BaseComponent class in componentUI.js
. This allows components to utilize the built-in data binding and key capture capabilities.
To interact with a chart, components should be derived from ContextTag. This tag automatically locates the cq-context
component that is parent to the tag, ensuring that the context knows about the tag and vice versa. By using this.context.stx
, components can reliably provide a reference to the chart object.
A third type of component called a DialogContentTag can be used for components that potentially need to interact with multiple charts. Dialogs are a perfect example, where a single dialog on a page may interact with any chart on the page depending on which button the user pressed. In this case this.context.stx
changes depending on the state of the tag.
Helpers
In addition to web components, the UI framework includes a set of classes called "Helpers". The job of a Helper is to bridge functionality between a component and a chart engine (i.e. Layout, StudyEdit). A Helper can also be used to implement data binding on a section of DOM that isn't componentized (i.e. StudyMenu).
Helpers are always associated with a particular chart context. They must be created in your JavaScript:
var context = new CIQ.UI.Context(stxx, document.querySelector("cq-context"));
var layout = new CIQ.UI.Layout(context);
Since Helpers do not live in the DOM, they rely on the context to connect them for data binding. They do this by advertising themselves with the method advertiseAs()
. Generally, you don't need to worry about Helpers unless you need to add additional bindings. If so, we recommend extending the CIQ.UI.Layout
prototype with additional methods.
Bindings
The UI framework uses attributes for binding. Three types of binding are supported:
-
stxtap - User click/tap (or hits enter in an input tag)
<div stxtap='handleClick()'>
will call the method handleClick() when the user clicks/taps on that div tag. The framework will look for the nearest parent object that has that function.You can also target Helpers with this code
<div stxtap='Layout.handleClick()'>
. In this case, the nearest ContextTag will activate the binding, and use its context to find an associated Layout helper.Example, bindings are automatically associated with the nearest parent component:
Let's add a toggle to the header that allows users to switch between day and night themes with a single click. The following will work in our sample templates.
<!-- <div class="icon-toggles ciq-toggles"> --> <cq-toggle id="toggle"><div stxtap="changeTheme()">Toggle Theme</div></cq-toggle> <!-- </div> --> <script> const themeToggle = document.querySelector('#toggle'); themeToggle.changeTheme = function () { const themeElement = document.querySelector('cq-themes') // find the cq-themes component let currentTheme = themeElement.getAttribute('theme') // store its current theme setting if (currentTheme === 'ciq-day') { // toggle between ciq-night and ciq-day themeElement.setAttribute('theme', 'ciq-night') } else { themeElement.setAttribute('theme', 'ciq-day') } } </script>
-
stxbind - Keeps DOM in sync with the contents of a JavaScript variable
Unlike more comprehensive data binding systems,
stxbind
defers the job of binding to a member call. For instance,<div stxbind='bindFunction()'>
simply calls the methodbindFunction()
when the component is instantiated. It is the job ofbindFunction()
to monitor a JS variable and update the DOM.Example, establish a binding:
In this simple example,
stxbind
is used to monitor and adjust the toggle'svalue
attribute based on the current chart theme when the page reloads. This allows us to simplify the changeTheme function by utilizing a ternary operator.<script> themeToggle.bindFunction = function () { let currentTheme = document.querySelector('cq-themes').getAttribute('theme') if (currentTheme === 'ciq-day') this.value = true; } // Update to changeTheme function used above themeToggle.changeTheme = function () { const theme = document.querySelector('cq-themes') theme.setAttribute('theme', this.value ? 'ciq-night' : 'ciq-day'); } </script>
- You can also set up a property of an object to be observed using CIQ.UI.observeProperty. When the property value changes, a listener function is executed.
Note: This method requires access to a chart engine.
This example builds off of the previous example and uses the
observeProperty
method inside of ourbindFunction
. In this case, we are monitoring thecq-themes
component, specifically itscurrentTheme
. This example keeps thecq-toggle
in sync with the current theme, regardless of how a user switches themes.<cq-toggle id="toggle"><div stxtap="changeTheme()"stxbind="bindFunction()"></div></cq-toggle> <script> const themeToggle = document.querySelector('#toggle'); const themeElement = document.querySelector('cq-themes') themeToggle.bindFunction = function (node) { const currentTheme = themeElement.theme; if (currentTheme === 'ciq-day') this.value = true; // updates value when page is refreshed CIQ.UI.observeProperty('currentTheme', themeElement, () => { node.innerText = themeElement.currentTheme.replace(/^ciq-(\w+)/, "$1").toUpperCase(); }) } </script>
- You can also set up a property of an object to be observed using CIQ.UI.observeProperty. When the property value changes, a listener function is executed.
-
stxsetget - Two-way binding
stxsetget is a convenience method for adding both stxtap and stxbind with a single attribute. The main difference is that "set" and "get" are prepended to the attribute value when called. Two-way binding is used for instance when building the radio button display menu in sample-template-advanced.html.
Of course, there is no restriction on including other data binding or templating engines if you have more demanding data binding needs.
Observing and modifying state
Attributes
ChartIQ web components provide observed attributes for dynamic customization and modification of component behavior and appearance, enabling enhanced UI customization beyond the native features in the ChartIQ library.
Below are some examples of web components and their attributes.
Web Component | Attributes |
---|---|
cq-drawing-palette |
"view", "active-tool", "docked" |
cq-dropdown |
"maximize", "noresize", "config" |
cq-color-picker |
"cq-active","cq-colors" |
cq-dialog |
"cq-title","cq-description", "cq-close-button" |
cq-toggle |
"action", "config, "stxtap", "toggles", "tooltip" |
cq-menu |
"binding", "config", "help-id", "icon", "reader", "responsive", "state", "text", etc... |
Emitters
Web component emitters in the ChartIQ architecture allow for the transmission of events and changes in state through attribute tags. These events can be listened to using custom React hooks or other methods. By changing an attribute, components can react to the event or state change, providing a more modern and customizable library for developers.
Note: The name of the event being emitted is the name of the component but in UpperCamelCase. For instance, in the example below, the name of the event emitted by <cq-drawing-palette>
is simply DrawingPalette. Copy/paste the below code into your console and then interact with the drawing palette to see its custom event details.
Example:
const palette = document.querySelector("cq-drawing-palette");
palette.addEventListener("DrawingPalette", (e) => {
console.log("the drawing palette did something");
console.log("this is what happened: ", e.detail);
});
Customizing HTML and CSS
Customizing the provided templates is really as easy as modifying the HTML and CSS. Simply delete a component from the HTML if you don't wish to use it. If you want to make it look different you can reorganize the HTML inside the component and modify the associated CSS.
The CSS used by the templates is actually built using SASS. The SASS is compiled into chartiq.css. You should never modify chartiq.css directly because this will make it very difficult to upgrade in the future. Instead, we recommend adding additional CSS in your own file and then including it after chartiq.css
. All CSS values can be overridden in this manner. Following this approach will guarantee easy upgrades.
Example, overriding the font size of cq-show-range:
cq-show-range {
font-size: 14px;
}
<link rel="stylesheet" type="text/css" href="chartiq/css/chartiq.css" />
<link rel="stylesheet" type="text/css" href="mycss.css" />
Note: An exception to this rule is if you wish to change the colors or fonts for the entire template. In this case, we recommend making a copy of css/chartiq.scss
. Change the variables to contain the colors and styles that you prefer. Then use a SASS builder to generate a new chartiq.css
file.
Component Specifics
Here are some examples of the commonly used web components found in our sample charts.
-
cq-toggle - creates a toggle div that can automatically be bound. See WebComponents.Toggle.
-
cq-clickable - creates an div that when clicked runs a method on a different component. See WebComponents.Clickable.
-
cq-dialog - creates a dialog that is centered on the screen. A
cq-dialog
should typically contain a component that is derived from CIQ.UI.DialogContentTag. Generally, you would callopen()
orclose()
on the inner content tag instead of interacting directly with the dialog. See WebComponents.Dialog.
Example, open a dialog:
<cq-dialog cq-title="Hello World" cq-close-button="false">
<!-- insert your HTML here -->
</cq-dialog>
<script>
document.querySelector("cq-dialog").open();
</script>
- cq-menu - creates a dropdown menu. Menus appear when tapped or clicked (not hovered). As of version 9.1.0,
cq-dropdown
is generally created automatically withincq-menu
, so you typically don't need to include it. The CSS for this component has been carefully constructed so that menuing is extremely lightweight. See WebComponents.Menu.
This example from sample-template-advanced
gets configured via defaultConfiguration.js
. Use it as a starting point for creating your menus.
<cq-menu
class="nav-dropdown ciq-display"
reader="Display"
config="display"
binding="Layout.chartType"
icon
help-id="display_dropdown"
tooltip
></cq-menu>;
- cq-color-picker - establishes a color picker component for the page. Only a single color picker exists on the page. It is relocated dynamically whenever it is opened. The color picker is triggered by a
cq-swatch
component which displays a clickable swatch of color. See WebComponents.ColorPicker.
See WebComponents.html for a full list of available components and their documentation.
Data Integration
Driver.Lookup (Symbol Search Engine)
The cq-lookup
and cq-lookup-dialog
tags require a Lookup.Driver helper to process "look ahead" (autocomplete) keystrokes and to fetch results. CIQ.ChartEngine.Driver.Lookup
provides a default implementation that queries against ChartIQ's symbol server.
The default lookup driver is defined in examples/feeds/symbolLookupChartIQ.js
and needs to be loaded to be available
To simplify the integration process, we suggest making a duplicate of the symbolLookupChartIQ.js
file and customizing the CIQ.ChartEngine.Driver.Lookup.ChartIQ
and CIQ.ChartEngine.Driver.Lookup.ChartIQ.prototype.acceptText
functions according to your specific requirements. This approach allows you to maintain the core structure of our sample Lookup.Driver while tailoring it to your needs. By doing so, you can ensure a seamless transition and take advantage of the existing structure and functionality.
Note: When implementing your customization, the acceptText()
method receives the user-entered text and any selected lookup filters. Results should be returned as an array of objects, each containing a data item (in whatever format you wish) and a display array with displayable values.
Example:
CIQ.ChartEngine.Driver.Lookup.ChartIQ = function (exchanges) {
this.exchanges = exchanges;
if (!this.exchanges)
// Modify this array to suit the needs of your chart
this.exchanges = [
// Exchanges
];
this.url = // your URL;
this.requestCounter = 0; //used to invalidate old requests
};
CIQ.ChartEngine.Driver.Lookup.ChartIQ.prototype.acceptText = function (
text,
filter,
maxResults,
cb
) {
// your code here
}
NameValueStore
Some supplied web components require a name value store in order to persist their state across sessions. By default, the library comes with a NameValueStore implementation that uses the browser's localStorage. You can however create your own which could use a network service for persistence.
To use an alternative store, you should first create a class that conforms to the NameValueStore interface. This should implement get, set and remove methods.
Example, create a custom NameValueStore:
const MyNVS = {
get: function(field, cb) {
cb(null, result);
},
set: function(field, value, cb) {
// set
},
remove: function(field, cb) {
// remove
}
};
Next, you will need to initialize the desired components with this NameValueStore.
cq-themes
and cq-views
currently use this interface to store values.
Example, initialize components with custom NameValueStore:
document.querySelector("cq-themes").initialize({
builtInThemes: { "ciq-day": "Day" },
nameValueStore: new MyNVS()
});
document.querySelector("cq-views").initialize({
nameValueStore: new MyNVS()
});
Advanced Topics
KeystrokeHub
This is a singleton helper that manages keystrokes. In HTML, you would typically register for key events on an input tag. The KeystrokeHub handles the more complicated problem of handling keystrokes that are independent of input tags. Examples include global hotkeys, passing keystrokes to a chart, or navigating the menuing system with keys.
You must initialize a KeystrokeHub with JavaScript code and associate it with a context. (You can optionally dynamically associate the context by calling setContext()
). The KeystrokeHub registers itself with the cq-ui-manager so that it is universally available.
Components receive keystrokes by registering "claims". The KeystrokeHub distributes keystrokes to all components who have staked a claim by calling their keyStroke()
method. A component can then decide whether to act on the keystroke, and if so, return true so that no other component acts on the stroke. It is the responsibility of the component to decide whether it should act. For instance, cq-scroll components only act on cursor up, cursor down, and enter keystrokes. Furthermore, they only act on them if the component itself is visible.
If a keystroke is not claimed by any component then the KeystrokeHub will attempt to satisfy any global hotkeys by calling CIQ.UI.KeystrokeHub.defaultHotKeys()
. A default implementation is provided in defaultConfiguration.js
, but you have the option to override this prototype method if desired.
For both components as well as hotkeys, the default browser key code will be passed for most keys. For special keys, a string is passed to indicate the key that was pressed. For instance, "up" is passed when the cursor up key is pressed.
Lifts
From time to time, an interactive page runs into formatting constraints. A typical constraint might occur in dialogs, where interactive (pop-up) data is hidden by the edge of the dialog. The most common example of this is when implementing a select-box inside of a dialog. Native select-boxes are ugly, but custom select-boxes get cut off when inside dialogs.
By adding the cq-lift
attribute to a tag, the cq-ui-manager
will temporarily "lift" the tag outside of its container, freeing it of its bounding box. It does this by using absolute positioning. When the tag is acted upon, the lift is released, and the tag goes back into its dialog. To see an example of cq-lift
in action, check out sample-template-multichart.html
and inspect the periodicity dropdowns that are next to the current symbol.
containerExecute
This provides a convenient pattern for nested composable components. containerExecute will traverse up an ancestor tree looking for a component that contains a given method.
As an example, consider the tag cq-close
tag. We would like to nest this tag arbitrarily inside any type of component and have it automatically close the parent component. But we might want to wrap it in some formatting, which decouples the tag in the DOM. In this circumstance, we have coded the cq-close
component to emit a containerExecute that will call the close()
method on the nearest parent that contains that method. So long as a tag implements this interface, cq-close
can be nested inside.
An analogy is exception handling. Calling containerExecute
is like throwing an exception. It will traverse up the stack until it finds a handler and then passes the message to that handler.
Resizables
Until recently, receiving resize events from DOM elements was not universally supported across browsers (only window resizing is an event in some browsers). In dynamic single page applications though, we frequently encounter interfaces that have DOM elements changing size based on user interactive. For instance, a menu may change in height as elements are added or removed.
Luckily, a workaround exists. The component library makes use of resize listeners that are based on the ResizeObserver API. Simply call CIQ.UI.addResizeListener(node, cb)
to receive resize events. Note, be sure to call CIQ.UI.removeResizeListener(node)
when cleaning up.
Additionally, any component registered this way will also have its resize()
method called whenever the window itself is resized. This allows dialogs and menus to resize themselves accordingly.
jQuery
As of version 8.1.0, the web components no longer require jQuery. However, if you do choose to use jQuery, the components remain fully compatible. If you have implemented custom web components that rely on jQuery, you may need to include the deprecated.js module which contains the library's deprecated jQuery methods.
Data binding mechanics
You must call CIQ.UI.begin()
in order to start data binding. This is primarily due to the potential for importing web components from other files. Once this has been called, components derived from BaseComponent automatically process their own data binding events.
You can dynamically create components and add them to the DOM. When components are attached, they are processed for data binding, but this processing only occurs once. If you remove a component and then add it elsewhere, the data bindings will not automatically change. In such cases, you need to call CIQ.UI.BaseComponent.buildReverseBindings and pass in the element that was moved or added after it was initially attached.
One of the complications with any framework is initialization. Many of the components require access to a cq-context
, but there is no guarantee that the CIQ.UI.Context
exists when those components are created. To address this, we leverage the DOM. Contexts are discovered by traversing the DOM. The actual CIQ.UI.Context
implementation is stored in the cq-context tag as document.querySelector("cq-context").CIQ.UI.context
. Each component also registers itself in document.querySelector("cq-context").CIQ.UI.Components[]
. In this way, whoever gets created last (the component or the context) is responsible for linking themselves up. This is done by calling the setContext()
method on the component itself.
Finally, this method of "implicit" data binding creates potential ambiguities. As a rule therefore, the framework requires that data bindings occur on their nearest ancestor component. In order to enforce this policy, and to ensure the existence of a full ancestor tree, bindings occur on the "nextTick" after a component is added to the DOM. This ensures that the DOM tree is fully established when all decisions about data binding occur.
Architectural Boundaries
While it is not a capability of the software, the architecture technically makes it possible (with additional syntax) for data bindings to target specific ancestors, or even unrelated components. However, since bindings occur at the time a component is added to the DOM, the architecture would not easily support "runtime" bindings - those that must be acted upon at the tick of user click.
CIQ.UI.observeProperty
provides a convenient and lightweight observable mechanism, however, its limits must be understood. CIQ.UI.observeProperty
binds directly to objects, not to a representation of an object chain. This means that a binding will not change if a parent object is replaced. This can lead to unintuitive results.
Example: Paste the following code into the console to see how CIQ.UI.observeProperty
will 'observe' the dataSegment
property and triggers a callback function when it updates.
CIQ.UI.observeProperty("dataSegment", stxx.chart, () =>
console.log(stxx.chart.lastQuote.Close)
);
ModalTag
You can derive your components from ModalTag in order to automatically give them modal capabilities. This means that when you mouse over the tag, stx.modalBegin()
and stx.modalEnd()
are called, disabling mouse interaction with the associated chart. A ModalTag is typically used when superimposing a component on to a chart, often as a cq-marker
. For this reason, ModalTag is derived from ContextTag and must have a cq-context
in its ancestor tree.
Some of the ChartIQ web components that are derived from ModalTag are:
makeFromTemplate
Instantiating templates actually takes a fair amount of boilerplate, namely because they exist as a DocumentFragment and not as an actual DOM element. makeFromTemplate encapsulates that functionality so that you can easily create a template.